package controlador;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import modelo.dao.PartidaRecordDAO;
import modelo.dto.PartidaRecord;
import vista.JPartida;

/**
 * Esta clase hace crea la ventana que se construye desde el paquete de vistas y adem�s contiene los diferentes
 * m�todos que hacen que la aplicaci�n cumpla su cometido. 
 * 
 * @author Lilianny Rodriguez 	C.I.: 19.323.400
 * @author Jose Jerez 			C.I.: 18.560.575
 * @author Jhoswar Fernandez	C.I.: 19.779.296
 * @author Leandro Oliva		C.I.: 20.187.193
 *
 */
public class ControladorPartida implements ActionListener {
	
	private JPartida 		ventanaPartida;
	private JPanel 			pnlImagenPartida;
	private boolean 		ganador;
	private boolean 		fin;
	private Double 			minutos;
	private String 			nivel;
	/** Esta variable maneja las opciones para las consultas de los menu*/
	private String 			nivel1;
	private String 			jugador;
	private String 			nivelBoton;
	private Vector<Integer> vectorGeneral = new Vector<Integer> ();
	private Vector<Integer> codigoSolucion 		= new Vector<Integer>(7);
	private Vector<Integer> codigoDado 			= new Vector<Integer>(7);
	private int 			ArrayBasico[] 		= new int[4];
	private int 			ArrayIntermedio[] 	= new int[5];
	private int 			ArrayAvanzado[] 	= new int[6];
	private int 			puntosGanados;
	private int 			tiempo;
	private int 			numeroColor;
	private int 			indiceArreglo;
	private int 			intentos		= 0;
	private int 			coincidencias	= 0;
	private int 			h;
	private int 			blancas			= 0;
	private int 			negras			= 0;
	private int 			negrasAqui;
	private int 			blancasAqui;
	private int 			altura			= 155;
	private int 			alturaTipo;
	private int 			anchoTipo;
	private int 			cantidad		= 0;
	
	
	private final int NIVEL_BASICO		= 4;
	private final int NIVEL_INTERMEDIO	= 5;
	private final int NIVEL_AVANZADO	= 6;
	
	public ControladorPartida() {
		this.ventanaPartida = new JPartida();
		this.ventanaPartida.setVisible(true);
		ventanaPartida.pedirJugador();
		ventanaPartida.pedirNivel();
		pnlImagenPartida = (JPanel) ventanaPartida.getContentPane();
		pnlImagenPartida.setLayout(null);
		nivel   = ventanaPartida.getLblDescripcionNivel().getText();
		jugador = ventanaPartida.getLblNombreJugador().getText();
		cargarArreglos();
		this.ventanaPartida.addListener(nivel, this);
		codigoSolucion = generarCodigoSecreto();
	}

	/**
	 * Este m�todo contiene las acciones que realizar� la aplicaci�n cuando el usuario haga sus selecciones
	 */
	public void actionPerformed(ActionEvent e) {
	
		colorearBotones(e);
		
		if (e.getActionCommand().equals("Comprobar") && cargada()) {
			intentos++;
			
			if ((nivel.equals("Basico") && intentos == 12) ||
				(nivel.equals("Intermedio") && intentos == 13) ||
				(nivel.equals("Avanzado") && intentos == 14) ) {
				
					llenarVectorDado();	
					ganador = contar(nivel);
					negrasAqui = negras;
					blancasAqui = blancas;
					dibujarBotonesBlancosNegros();
					fin = true;
					
			} else {
				llenarVectorDado();	
				ganador = contar(nivel);
				negrasAqui = negras;
				blancasAqui = blancas;
				dibujarBotonesBlancosNegros();
				fin = ganador;
			}
			
			if (fin) {
				mostrarMensaje(ganador, intentos);
			} else {
				habilitarSiguiente();	
			}
			
		} else if (e.getActionCommand().equals("Nivel Basico")) {
			nivel1 = "Basico";
			new ControladorConsulta(nivel1);
		} else if (e.getActionCommand().equals("Nivel Intermedio")) {
			nivel1 = "Intermedio";
			new ControladorConsulta(nivel);
		} else if (e.getActionCommand().equals("Nivel Avanzado")) {
			nivel1 = "Avanzado";
			new ControladorConsulta(nivel);
		}
	}
	
	/**
	 * Este metodo carga los arreglos con -1 para evitar errores
	 */
	public void cargarArreglos() {
		for (int y = 0; y < 4; y++)
			 ArrayBasico[y] = -1;
		for (int t = 0; t < 5; t++)
			 ArrayIntermedio[t] = -1;
		for (int q = 0; q < 6; q++)
			 ArrayAvanzado[q] = -1;
	}
	
	/**
	 * Este m�todo se encarga de dibujar los botones blancos y negros para indicarle al usuario que tan cerca est� de adivinar el c�digo secreto
	 */
	public void dibujarBotonesBlancosNegros() {
		
		if (ventanaPartida.getValorBasico() == true) {
			cantidad=12;
			alturaTipo=38;
			anchoTipo=320;
		} else if (ventanaPartida.getValorIntermedio() == true) {
			cantidad=13;
			alturaTipo=38;
			anchoTipo=350;
		} else if (ventanaPartida.getValorAvanzado() == true) {
			cantidad=14;
			alturaTipo=38;
			anchoTipo=385;
		}
		
		if (intentos < cantidad) {
			int total = 0;
			JButton boton []= new JButton[blancasAqui + negrasAqui];
			if (negrasAqui == 0  && blancasAqui== 0) {
				JButton boton1 []= new JButton[codigoSolucion.size()];
				for (int i = 0; i < codigoSolucion.size(); i++) {
					boton1[i] = new JButton();
					boton1[i].setVisible(true);
					boton1[i].setEnabled(false);
			    	boton1[i].setBackground(Color.LIGHT_GRAY);
			    	boton1[i].setBounds(anchoTipo, altura, 19, 17);
			    	pnlImagenPartida.add(boton1[i],null);
			    	boton1[i].revalidate();
			    	boton1[i].repaint();
			    	anchoTipo = anchoTipo + 19;
				}
			      altura = altura + alturaTipo;
			      
			} else if ((negrasAqui != 0) || (blancasAqui != 0)) {
				total = negrasAqui + blancasAqui;					 
				 for (int i = 0; i < total; i++) {
				    if(blancasAqui > 0) {
						boton[i] = new JButton();
						boton[i].setVisible(true);
						boton[i].setBackground(Color.WHITE);
						boton[i].setEnabled(false);
				    	boton[i].setBounds(anchoTipo, altura, 19, 17);
				    	pnlImagenPartida.add(boton[i],null);    	
				    	boton[i].revalidate();
				    	boton[i].repaint();
				    	anchoTipo = anchoTipo + 19;
				    	blancasAqui--;
					}
				    if (negrasAqui > 0) {
						boton[i] = new JButton();
						boton[i].setVisible(true);
						boton[i].setEnabled(false);
				    	boton[i].setBackground(Color.black);
				    	boton[i].setBounds(anchoTipo, altura, 19, 17);
				    	pnlImagenPartida.add(boton[i],null);
				    	boton[i].revalidate();
				    	boton[i].repaint();
				    	anchoTipo = anchoTipo + 19;
				    	negrasAqui--;
					}
				 
				 }
				 altura = altura + alturaTipo;
			}
		}
	}
	
	/**
	 * Este m�todo se encarga de llenar un vector seg�n la combinaci�n de colores elegida por el usuario y el nivel
	 */
	public void llenarVectorDado() {
		
		vectorGeneral.clear();
		
		if (nivel.equals("Basico")) {
			for (int a = 0; a < 4; a++) {
			     numeroColor =  ArrayBasico[a];    
			     vectorGeneral.add(a, numeroColor);
			}
			for (int y = 0; y < 4; y++) {
				 ArrayBasico[y] = -1;
			}
		} else if (nivel.equals("Intermedio")) {
				for (int a = 0; a < 5; a++) {
				    numeroColor =  ArrayIntermedio[a];
				    vectorGeneral.add(a, numeroColor);
				}
				for (int t = 0; t < 5; t++){
					 ArrayIntermedio[t] = -1;
				}
		} else if (nivel.equals("Avanzado")) {
				for (int a= 0; a<6; a++) {
				    numeroColor = ArrayAvanzado[a];
				    vectorGeneral.add(a, numeroColor);
				}
				for (int q = 0; q < 6; q++) {
					 ArrayAvanzado[q] = -1;
				}
		}
	}
	
	/**
	 * Este m�todo se encarga de pasarle a los botones el color seg�n la combinaci�n elegida por el usuario
	 * @param ActionEvent e
	 */
	public void colorearBotones(ActionEvent e) {
		
		if (nivel.equals("Basico")) {
			
			 for (int i = 0; i < 12; i++) {
			 	for (int j = 0; j < 4; j++) {
			 		if (ventanaPartida.getBotonera().numero() != -1) {
			 		   if ((e.getActionCommand().equals((ventanaPartida.getPnlBasico().getButton(i,j).getActionCommand())))) {
				 		   ventanaPartida.getPnlBasico().getButton(i,j).setBackground(ventanaPartida.getBotonera().pasala());
				 		   numeroColor = ventanaPartida.getBotonera().numero();
				 	       ArrayBasico[j] = numeroColor; 
			 		   }
			 		}
				}
			 }
		} else if (nivel.equals("Intermedio")) {
			 for (int i = 0; i < 13; i++) {
			 	for (int j = 0; j < 5; j++) {
			 		if (ventanaPartida.getBotonera().numero() != -1) {
			 		   if ((e.getActionCommand().equals((ventanaPartida.getPnlIntermedio().getButton(i,j).getActionCommand())))) {
			 			   ventanaPartida.getPnlIntermedio().getButton(i,j).setBackground(ventanaPartida.getBotonera().pasala());
			 			   numeroColor = ventanaPartida.getBotonera().numero();
			 			   ArrayIntermedio[j] = numeroColor;
			 		   }
			 		}
				 }
			 }
		 } else if (nivel.equals("Avanzado")) {
			for (int i = 0; i < 14; i++){
			 	for (int j = 0; j < 6; j++) {
			 		if (ventanaPartida.getBotonera().numero() != -1) {
				 		if ((e.getActionCommand().equals((ventanaPartida.getPnlAvanzado().getButton(i,j).getActionCommand())))) {
					 		ventanaPartida.getPnlAvanzado().getButton(i,j).setBackground(ventanaPartida.getBotonera().pasala());
					 		 numeroColor = ventanaPartida.getBotonera().numero();
					 		 ArrayAvanzado[j] = numeroColor;
					   }
			 		}
			 	}
			}
		}
	}
	
	/**
	 * Este m�todo se encarga de verificar que la combinaci�n de colores que el usuario ingreso coincida con el c�digo secreto. Esto se realiza seg�n el nivel 
	 * @param nivelJuego
	 * @return boolean
	 */
	public boolean contar(String nivelJuego) {
		
		h 				= 0;
		negras 			= 0;
		blancas 		= 0;
		coincidencias 	= 0;
		int i			= 0;
		
		if (nivel.equals("Basico")) {
			codigoDado = vectorGeneral;
		} else if (nivel.equals("Intermedio")) {
			codigoDado = vectorGeneral;
		} else if (nivel.equals("Avanzado")) {
			codigoDado = vectorGeneral;
		}
		
		for (i = 0; i < codigoSolucion.size(); i++) {
			
			if (codigoSolucion.elementAt(i) == codigoDado.elementAt(h)){
				negras++;
				h++;
			} else{
		    	h++;
			}
		}
		
		for (i = 0; i < codigoSolucion.size(); i++){
			for(h = 0; h < codigoDado.size(); h++){
				if(codigoSolucion.elementAt(i) == codigoDado.elementAt(h)){
					coincidencias++;
					codigoDado.removeElementAt(h);
					break;
				}
			}
		}
		blancas = coincidencias - negras;
		
		if(nivelJuego.equals("Basico")){
			if (negras == NIVEL_BASICO){
				return true;
			} else {
				return false;
			}
		} else if (nivelJuego.equals("Intermedio")){
			if (negras == NIVEL_INTERMEDIO){
				return true;
			} else {
				return false;
			}
		} else if (nivelJuego.equals("Avanzado")) {
			if (negras == NIVEL_AVANZADO){
				return true;
			} else {
				return false;
			}
		} return false;
		
	}
	
	/**
	 * Este metodo se encarga de validar que el arreglo este cargado para habilitar el bot�n de comprobar
	 * @return boolean
	 */
	public boolean cargada() {
		
		if (nivel.equals("Basico")) { 
			for (int a = 0; a < 4; a++) {
				indiceArreglo = ArrayBasico[a];
			    if (indiceArreglo == -1) {
			        ventanaPartida.setEnabledComprobar(false); 
			    	return false;
			    }
			}
		} else if (nivel.equals("Intermedio")) {
			for (int a = 0; a < 4; a++) {
				indiceArreglo = ArrayIntermedio[a];
			    if (indiceArreglo == -1) {
			    	ventanaPartida.setEnabledComprobar(false); 
			    	return false;
			    }
			}
		} else if (nivel.equals("Avanzado")) {
			for (int a = 0; a < 6; a++) {
				indiceArreglo = ArrayAvanzado[a];
			    if (indiceArreglo == -1) {
				   ventanaPartida.setEnabledComprobar(false); 
				   return false;
			    }
			}
		}
		
		return true;
	}
	
	/**
	 * Este m�todo genera el c�digo secr�to, el cual debe ser adivinado luego por el usuario. 
	 * Retorna un vector que contiene dicho c�digo
	 * 
	 * @return Vector<Integer>
	 */
	private Vector<Integer> generarCodigoSecreto() {
		
		Random rnd = new Random();
		rnd.setSeed(new Date().getTime());
		
		if (nivel.equals("Basico")) {

			Vector<Integer> vectorB = new Vector<Integer>(3);
		
	    		for (int i = 0; i < 4; i++) {
	    			int a = (int) (Math.random() * 7);
	    			vectorB.add(a);
	    		}
	    		return vectorB;
			}
	    
		else if (nivel.equals("Intermedio")) {
	    	
	    	Vector<Integer> vectorI = new Vector<Integer> (4);
	    	
	    		for(int i = 0; i < 5; i++){
	    			int b = (int) (Math.random() * 7);
	    			vectorI.add(b);
	    		}
	    		return vectorI;
	    			
	    	}
		
	    else if (nivel.equals("Avanzado")) {
	    	
	    	Vector<Integer> vectorA = new Vector<Integer> (5);
	    
	    		for(int i = 0; i < 6; i++){
	    			int c = (int) (Math.random() * 7);
	                vectorA.add(c);
	    		}
	    		return vectorA;
	
	    	}
		return null;

	}
	
	/**
	 * Este m�todo muestra una pantalla que le indicar� al usuario cuando haya terminado y le comunicar� si
	 * ha ganado o ha perdido, adem�s calcula el puntaje obtenido y hace la llamada al m�todo guardar si es que el usuario gan� la partida.
	 * 
	 * @param ganador
	 * @param intentos
	 */
	private void mostrarMensaje(boolean ganador, int intentos) {
		if (!ganador) {
			ventanaPartida.crearMensajePerdedor();
			new ControladorBienvenida();
			ventanaPartida.setVisible(false);
		} else {
			calcularPuntaje(intentos);
			ventanaPartida.crearMensajeGanador(puntosGanados);
			guardarPartida();
			new ControladorBienvenida();
			ventanaPartida.setVisible(false);
		}
	}

	/**
	 * Este m�todo hace la llamada a los m�todos de registrar de la clase PartidaRecordDAO y con �l guarda el objeto
	 * PartidaRecord con los valores de sus atributos.
	 */
	private void guardarPartida() {
		PartidaRecordDAO partidaRecordDAO = new PartidaRecordDAO();
		minutos = ventanaPartida.getjLabelCronometro1().totalEnMinutos();
		PartidaRecord partidaRecord = new PartidaRecord(nivel, jugador, puntosGanados, intentos, minutos);
		partidaRecordDAO.registrarPartidaRecord(partidaRecord);
	}
	
	/**
	 * Este m�todo calcula el puntaje obtenido por el usuario con un patr�n que incluye los intentos que hizo
	 * el jugador y el tiempo.
	 * @param intentos
	 */
	private void calcularPuntaje(int intentos) {
		double puntaje = 0;
		minutos = ventanaPartida.getjLabelCronometro1().totalEnMinutos();
		puntaje = (intentos / minutos) * 1500;
		puntosGanados = (int)puntaje;
	}
	
	/**
	 * Este m�todo hace la interacci�n con la vista para que se hagan visibles y se inhabiliten los botones del panel
	 *  y as� poder seguir jugando
	 */
	private void habilitarSiguiente() {

		if (nivel.equals("Basico")) {
			ventanaPartida.botonesVisibles(true,intentos,NIVEL_BASICO, nivel);
			ventanaPartida.bloquearBotones(false, intentos,NIVEL_BASICO, nivel);
		} else if (nivel.equals("Intermedio")) {
			ventanaPartida.botonesVisibles(true,intentos,NIVEL_INTERMEDIO, nivel);
			ventanaPartida.bloquearBotones(false, intentos,NIVEL_INTERMEDIO, nivel);
		} else if (nivel.equals("Avanzado")) {
			ventanaPartida.botonesVisibles(true,intentos,NIVEL_AVANZADO, nivel);
			ventanaPartida.bloquearBotones(false, intentos,NIVEL_AVANZADO, nivel);
		}
	}
	
	
}
